package fons.navigator.views.quadrant;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Vector;

import org.apache.batik.ext.awt.LinearGradientPaint;

import com.google.common.collect.Sets;

import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.nodes.PText;
import edu.umd.cs.piccolo.util.PBounds;
import edu.umd.cs.piccolox.util.PFixedWidthStroke;
import fons.model.ontology.Dimension;

public class ValueGrid extends PNode {
	private static final long serialVersionUID = 1L;
	
	private final static Font LEGEND_FONT = new Font("Arial", Font.PLAIN, 11);
	private final static Stroke GRID_STROKE = 
		new PFixedWidthStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, 10.0f,
							  new float[] { 5.0f, 5.0f }, 1.0f);
    private final static Paint GRID_STROKE_PAINT = new Color (50, 50, 50, 150); 
    private final static Font NAME_FONT = new Font("Arial", Font.BOLD, 14);
	
	private final PPath grid;
	private final VisualSpiral visualSpiral;
	private final List<PText> xLegends;
	private final List<PText> yLegends;
	
	private final int count = 10;
	private final double width = 200;
	private final double xSpacing = width / count;
	
	private final double height = 200;
	private final double ySpacing = height / count;
	
	private final PPath xCaption;
	private final PPath yCaption;
	
	private final PText xName;
	private final PText yName;
	
	public ValueGrid(VisualSpiral visualSpiral) {
		this.visualSpiral = visualSpiral;
		this.xLegends = new Vector<PText>();
		this.yLegends = new Vector<PText>();
		this.grid = new PPath();
				
		StringBuilder xBuilder = new StringBuilder("-   X = ");
		boolean first = true;
		for (Dimension different: Sets.difference(visualSpiral.getXFilters(), visualSpiral.getYFilters())) {
			if (!first) xBuilder.append(", ");
			xBuilder.append(different.getName());
			first = false;
		}
		first = true;
		StringBuilder yBuilder = new StringBuilder("+   Y = ");
		for (Dimension different: Sets.difference(visualSpiral.getYFilters(), visualSpiral.getXFilters())) {
			if (!first) yBuilder.append(", ");
			yBuilder.append(different.getName());
			first = false;
		}
		xBuilder.append("    +");
		yBuilder.append("    -");
		
		this.xName = new PText(xBuilder.toString());
		this.xName.setFont(NAME_FONT);
		this.yName = new PText(yBuilder.toString());
		this.yName.rotateInPlace(Math.toRadians(90));
		this.yName.setFont(NAME_FONT);
		
		for (int x = 0; x < count; ++x) {
			grid.append(new Line2D.Double(xSpacing * x, 0, xSpacing * x, height), false);
			
			if (x != 0) {
				PText legend = new PText();
				legend.setFont(LEGEND_FONT);
				legend.rotate(Math.toRadians(90));
				xLegends.add(legend);
				addChild(legend);
			}
		}

		for (int y = 0; y < count; ++y) {
			grid.append(new Line2D.Double(0, ySpacing * y, width, ySpacing * y), false);
			
			if (y != 0) {
				PText legend = new PText();
				legend.setFont(LEGEND_FONT);
				yLegends.add(legend);
				addChild(legend);
			}
		}

		addChild(grid);
		grid.setStroke(GRID_STROKE);
		grid.setStrokePaint(GRID_STROKE_PAINT);
		
		xCaption = new PPath(new Rectangle2D.Double(0, 0, 20, 20));
		yCaption = new PPath(new Rectangle2D.Double(0, 0, 20, 20));
						
		addChild(xCaption);
		addChild(yCaption);
		
		xCaption.moveToBack();
		yCaption.moveToBack();
		
		PCamera cam = visualSpiral.getCamera();
		
		Point2D origin = new Point2D.Double(
			visualSpiral.getXMinProjection(),
			visualSpiral.getYMinProjection());
		
		cam.viewToLocal(origin);
		
		Point2D max = new Point2D.Double(
			visualSpiral.getXMaxProjection(),
			visualSpiral.getYMaxProjection());
		
		cam.viewToLocal(max);
		
		GradientPaint p = new GradientPaint(
				origin,
				new Color(0, 255, 0, 100),
				max,
				new Color(255, 0, 255, 100));
		
		xCaption.setPaint(p);
		xCaption.setStroke(null);
		yCaption.setPaint(p);
		yCaption.setStroke(null);
		
		addChild(xName);
		addChild(yName);
	}
	
	private boolean initialized = false;
	
	public void update() {
		final PCamera cam = visualSpiral.getCamera();
		final PBounds cb = cam.getViewBounds();
		final PBounds b = cam.getBoundsReference();
		
		Point2D viewOrigin = cam.getViewBounds().getOrigin();
		
		final double viewOriginX = visualSpiral.xToValue(viewOrigin.getX());
		final double viewOriginY = visualSpiral.yToValue(viewOrigin.getY());
		final double viewMaxX = visualSpiral.xToValue(viewOrigin.getX() + cb.width);
		final double viewMaxY = visualSpiral.yToValue(viewOrigin.getY() + cb.height);
		
		final double stepX = (viewMaxX - viewOriginX) / count;
		final double stepY = (viewMaxY - viewOriginY) / count;
				
		final double xSpacing = b.width / count;
		final double ySpacing = b.height / count;
		
		int i = 1;
		for (PText legend: xLegends) {
			legend.setText(Double.toString((int) (100*(viewOriginX + i * stepX)) / 100.0));
			legend.setGlobalTranslation(new Point2D.Double(i * xSpacing + legend.getHeight(), b.height - 80));
			++i;
		}
		
		i = 1;
		for (PText legend: yLegends) {
			legend.setText(Double.toString((int) (100*(viewOriginY + i * stepY)) / 100.0));
			legend.setGlobalTranslation(new Point2D.Double(b.width - 80, i * ySpacing));
			++i;
		}
		
		grid.setBounds(visualSpiral.getCamera().getBounds());
		
		xCaption.setBounds(0, b.height-40, b.width-40, 40);
		yCaption.setBounds(b.width-40, 0, 40, b.height-40);
		
		if (!initialized) {
			Point2D origin = new Point2D.Double(
				visualSpiral.getXMinProjection(),
				visualSpiral.getYMinProjection());
			
			cam.viewToLocal(origin);
			Point2D max = new Point2D.Double(
				visualSpiral.getXMaxProjection(),
				visualSpiral.getYMaxProjection());
			cam.viewToLocal(max);
			
			final double avgStopX = visualSpiral.getXAvgValue() / visualSpiral.getXSpanValue();
			float[] stopsX = { 0.0f, (float) avgStopX, 1.0f };
			Color[] colorsX = { new Color(255, 0, 0, 200), new Color(255, 255, 0), new Color(0, 255, 0, 255) };
			
			LinearGradientPaint px = new LinearGradientPaint(
					new Point2D.Double(origin.getX(), 0),
					new Point2D.Double(max.getX(), 0),
					stopsX, colorsX);
			
			final double avgStopY = visualSpiral.getYAvgValue() / visualSpiral.getYSpanValue();
			float[] stopsY = { 0.0f, (float) avgStopY, 1.0f };
			Color[] colorsY = { new Color(255, 0, 0, 200), new Color(255, 255, 0), new Color(0, 255, 0, 255) };
			
			LinearGradientPaint py = new LinearGradientPaint(
					new Point2D.Double(0, origin.getY()),
					new Point2D.Double(0, max.getY()),
					stopsY, colorsY);
			
			xCaption.setPaint(px);
			xCaption.setStroke(null);
			yCaption.setPaint(py);
			yCaption.setStroke(null);
			
			xName.setOffset(b.width/2 - xName.getWidth()/2, b.height-xName.getHeight()-10);
			yName.setOffset(b.width-10, b.height/2 - yName.getWidth()/2);
		}
	}
}
